﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class NewBehaviourScript {
    [MenuItem ("Tools/CalAvgNormal")]
    public static void CalAvgNormal () {
        MeshFilter[] meshFilters = Selection.activeGameObject.GetComponentsInChildren<MeshFilter> ();
        foreach (var meshFilter in meshFilters) {
            Mesh mesh = meshFilter.sharedMesh;
            WirteAverageNormalToTangent (mesh);
        }

        SkinnedMeshRenderer[] skinMeshRenders = Selection.activeGameObject.GetComponentsInChildren<SkinnedMeshRenderer> ();
        foreach (var skinMeshRender in skinMeshRenders) {
            Mesh mesh = skinMeshRender.sharedMesh;
            WirteAverageNormalToTangent (mesh);
        }
    }

    private static void WirteAverageNormalToTangent (Mesh mesh) {
        var averageNormalHash = new Dictionary<Vector3, Vector3> ();
        for (var j = 0; j < mesh.vertexCount; j++) {
            if (!averageNormalHash.ContainsKey (mesh.vertices[j])) {
                averageNormalHash.Add (mesh.vertices[j], mesh.normals[j]);
            } else {
                averageNormalHash[mesh.vertices[j]] += mesh.normals[j];
            }
        }

        var averageNormals = new Vector3[mesh.vertexCount];
        for (var j = 0; j < mesh.vertexCount; j++) {
            averageNormals[j] = averageNormalHash[mesh.vertices[j]].normalized;
        }

        var tangents = mesh.tangents;
        var normals = mesh.normals;
        var uv2 = new Vector3[mesh.vertexCount];
        var uv3 = new Vector4[mesh.vertexCount];
        for (var j = 0; j < mesh.vertexCount; j++) {
            Vector3 normal = normals[j].normalized;
            Vector3 tangent = tangents[j];
            tangent = tangent.normalized;
            var biNormal = (Vector3.Cross(normal, tangent)*tangents[j].w).normalized;
            var TBN = new Matrix4x4();
            TBN.SetRow(0, new Vector4(tangent.x,tangent.y,tangent.z,0));
            TBN.SetRow(1, new Vector4(biNormal.x,biNormal.y,biNormal.z,0));
            TBN.SetRow(2, new Vector4(normal.x,normal.y,normal.z,0));
            TBN.SetRow(3, new Vector4(0,0,0,1));

            uv2[j] = TBN.MultiplyVector(averageNormals[j]);
            uv3[j] = averageNormals[j];
        }
        mesh.SetUVs(1, new List<Vector3>(uv2));
        mesh.SetUVs(2, new List<Vector4>(uv3));
    }
}